using System;
using UnityEngine;

namespace DanielSig.UnityExtensions
{
	public static class XVector3
	{
		public const float DEFAULT_UPWARDS_MODIFIER = 0.2F;
		public static Color DebugColor = Color.red;
		
		#region REORDER
		#region VECTOR 2
		public static Vector2 XX(this Vector3 v){ return new Vector2(v.x, v.x); }
		public static Vector2 XY(this Vector3 v){ return new Vector2(v.x, v.y); }
		public static Vector2 XZ(this Vector3 v){ return new Vector2(v.x, v.z); }
		
		public static Vector2 YX(this Vector3 v){ return new Vector2(v.y, v.x); }
		public static Vector2 YY(this Vector3 v){ return new Vector2(v.y, v.y); }
		public static Vector2 YZ(this Vector3 v){ return new Vector2(v.y, v.z); }
		
		public static Vector2 ZX(this Vector3 v){ return new Vector2(v.z, v.x); }
		public static Vector2 ZY(this Vector3 v){ return new Vector2(v.z, v.y); }
		public static Vector2 ZZ(this Vector3 v){ return new Vector2(v.z, v.z); }
		#endregion
		#region VECTOR 3
		public static Vector3 XXX(this Vector3 v){ return new Vector3(v.x, v.x, v.x); }
		public static Vector3 XXY(this Vector3 v){ return new Vector3(v.x, v.x, v.y); }
		public static Vector3 XXZ(this Vector3 v){ return new Vector3(v.x, v.x, v.z); }
		public static Vector3 XYX(this Vector3 v){ return new Vector3(v.x, v.y, v.x); }
		public static Vector3 XYY(this Vector3 v){ return new Vector3(v.x, v.y, v.y); }
		public static Vector3 XYZ(this Vector3 v){ return v; }
		public static Vector3 XZX(this Vector3 v){ return new Vector3(v.x, v.z, v.x); }
		public static Vector3 XZY(this Vector3 v){ return new Vector3(v.x, v.z, v.y); }
		public static Vector3 XZZ(this Vector3 v){ return new Vector3(v.x, v.z, v.z); }
		
		public static Vector3 YXX(this Vector3 v){ return new Vector3(v.y, v.x, v.x); }
		public static Vector3 YXY(this Vector3 v){ return new Vector3(v.y, v.x, v.y); }
		public static Vector3 YXZ(this Vector3 v){ return new Vector3(v.y, v.x, v.z); }
		public static Vector3 YYX(this Vector3 v){ return new Vector3(v.y, v.y, v.x); }
		public static Vector3 YYY(this Vector3 v){ return new Vector3(v.y, v.y, v.y); }
		public static Vector3 YYZ(this Vector3 v){ return new Vector3(v.y, v.y, v.z); }
		public static Vector3 YZX(this Vector3 v){ return new Vector3(v.y, v.z, v.x); }
		public static Vector3 YZY(this Vector3 v){ return new Vector3(v.y, v.z, v.y); }
		public static Vector3 YZZ(this Vector3 v){ return new Vector3(v.y, v.z, v.z); }
		
		public static Vector3 ZXX(this Vector3 v){ return new Vector3(v.z, v.x, v.x); }
		public static Vector3 ZXY(this Vector3 v){ return new Vector3(v.z, v.x, v.y); }
		public static Vector3 ZXZ(this Vector3 v){ return new Vector3(v.z, v.x, v.z); }
		public static Vector3 ZYX(this Vector3 v){ return new Vector3(v.z, v.y, v.x); }
		public static Vector3 ZYY(this Vector3 v){ return new Vector3(v.z, v.y, v.y); }
		public static Vector3 ZYZ(this Vector3 v){ return new Vector3(v.z, v.y, v.z); }
		public static Vector3 ZZX(this Vector3 v){ return new Vector3(v.z, v.z, v.x); }
		public static Vector3 ZZY(this Vector3 v){ return new Vector3(v.z, v.z, v.y); }
		public static Vector3 ZZZ(this Vector3 v){ return new Vector3(v.z, v.z, v.z); }
		#endregion
		#region VECTOR 4
		public static Vector4 XXXX(this Vector3 v){ return new Vector4(v.x, v.x, v.x, v.x); }
		public static Vector4 XXXY(this Vector3 v){ return new Vector4(v.x, v.x, v.x, v.y); }
		public static Vector4 XXXZ(this Vector3 v){ return new Vector4(v.x, v.x, v.x, v.z); }
		public static Vector4 XXYX(this Vector3 v){ return new Vector4(v.x, v.x, v.y, v.x); }
		public static Vector4 XXYY(this Vector3 v){ return new Vector4(v.x, v.x, v.y, v.y); }
		public static Vector4 XXYZ(this Vector3 v){ return new Vector4(v.x, v.x, v.y, v.z); }
		public static Vector4 XXZX(this Vector3 v){ return new Vector4(v.x, v.x, v.z, v.x); }
		public static Vector4 XXZY(this Vector3 v){ return new Vector4(v.x, v.x, v.z, v.y); }
		public static Vector4 XXZZ(this Vector3 v){ return new Vector4(v.x, v.x, v.z, v.z); }
		
		public static Vector4 XYXX(this Vector3 v){ return new Vector4(v.x, v.y, v.x, v.x); }
		public static Vector4 XYXY(this Vector3 v){ return new Vector4(v.x, v.y, v.x, v.y); }
		public static Vector4 XYXZ(this Vector3 v){ return new Vector4(v.x, v.y, v.x, v.z); }
		public static Vector4 XYYX(this Vector3 v){ return new Vector4(v.x, v.y, v.y, v.x); }
		public static Vector4 XYYY(this Vector3 v){ return new Vector4(v.x, v.y, v.y, v.y); }
		public static Vector4 XYYZ(this Vector3 v){ return new Vector4(v.x, v.y, v.y, v.z); }
		public static Vector4 XYZX(this Vector3 v){ return new Vector4(v.x, v.y, v.z, v.x); }
		public static Vector4 XYZY(this Vector3 v){ return new Vector4(v.x, v.y, v.z, v.y); }
		public static Vector4 XYZZ(this Vector3 v){ return new Vector4(v.x, v.y, v.z, v.z); }
		
		public static Vector4 XZXX(this Vector3 v){ return new Vector4(v.x, v.z, v.x, v.x); }
		public static Vector4 XZXY(this Vector3 v){ return new Vector4(v.x, v.z, v.x, v.y); }
		public static Vector4 XZXZ(this Vector3 v){ return new Vector4(v.x, v.z, v.x, v.z); }
		public static Vector4 XZYX(this Vector3 v){ return new Vector4(v.x, v.z, v.y, v.x); }
		public static Vector4 XZYY(this Vector3 v){ return new Vector4(v.x, v.z, v.y, v.y); }
		public static Vector4 XZYZ(this Vector3 v){ return new Vector4(v.x, v.z, v.y, v.z); }
		public static Vector4 XZZX(this Vector3 v){ return new Vector4(v.x, v.z, v.z, v.x); }
		public static Vector4 XZZY(this Vector3 v){ return new Vector4(v.x, v.z, v.z, v.y); }
		public static Vector4 XZZZ(this Vector3 v){ return new Vector4(v.x, v.z, v.z, v.z); }
		
		
		
		public static Vector4 YXXX(this Vector3 v){ return new Vector4(v.y, v.x, v.x, v.x); }
		public static Vector4 YXXY(this Vector3 v){ return new Vector4(v.y, v.x, v.x, v.y); }
		public static Vector4 YXXZ(this Vector3 v){ return new Vector4(v.y, v.x, v.x, v.z); }
		public static Vector4 YXYX(this Vector3 v){ return new Vector4(v.y, v.x, v.y, v.x); }
		public static Vector4 YXYY(this Vector3 v){ return new Vector4(v.y, v.x, v.y, v.y); }
		public static Vector4 YXYZ(this Vector3 v){ return new Vector4(v.y, v.x, v.y, v.z); }
		public static Vector4 YXZX(this Vector3 v){ return new Vector4(v.y, v.x, v.z, v.x); }
		public static Vector4 YXZY(this Vector3 v){ return new Vector4(v.y, v.x, v.z, v.y); }
		public static Vector4 YXZZ(this Vector3 v){ return new Vector4(v.y, v.x, v.z, v.z); }
		
		public static Vector4 YYXX(this Vector3 v){ return new Vector4(v.y, v.y, v.x, v.x); }
		public static Vector4 YYXY(this Vector3 v){ return new Vector4(v.y, v.y, v.x, v.y); }
		public static Vector4 YYXZ(this Vector3 v){ return new Vector4(v.y, v.y, v.x, v.z); }
		public static Vector4 YYYX(this Vector3 v){ return new Vector4(v.y, v.y, v.y, v.x); }
		public static Vector4 YYYY(this Vector3 v){ return new Vector4(v.y, v.y, v.y, v.y); }
		public static Vector4 YYYZ(this Vector3 v){ return new Vector4(v.y, v.y, v.y, v.z); }
		public static Vector4 YYZX(this Vector3 v){ return new Vector4(v.y, v.y, v.z, v.x); }
		public static Vector4 YYZY(this Vector3 v){ return new Vector4(v.y, v.y, v.z, v.y); }
		public static Vector4 YYZZ(this Vector3 v){ return new Vector4(v.y, v.y, v.z, v.z); }
		
		public static Vector4 YZXX(this Vector3 v){ return new Vector4(v.y, v.z, v.x, v.x); }
		public static Vector4 YZXY(this Vector3 v){ return new Vector4(v.y, v.z, v.x, v.y); }
		public static Vector4 YZXZ(this Vector3 v){ return new Vector4(v.y, v.z, v.x, v.z); }
		public static Vector4 YZYX(this Vector3 v){ return new Vector4(v.y, v.z, v.y, v.x); }
		public static Vector4 YZYY(this Vector3 v){ return new Vector4(v.y, v.z, v.y, v.y); }
		public static Vector4 YZYZ(this Vector3 v){ return new Vector4(v.y, v.z, v.y, v.z); }
		public static Vector4 YZZX(this Vector3 v){ return new Vector4(v.y, v.z, v.z, v.x); }
		public static Vector4 YZZY(this Vector3 v){ return new Vector4(v.y, v.z, v.z, v.y); }
		public static Vector4 YZZZ(this Vector3 v){ return new Vector4(v.y, v.z, v.z, v.z); }
		
		
		public static Vector4 ZXXX(this Vector3 v){ return new Vector4(v.z, v.x, v.x, v.x); }
		public static Vector4 ZXXY(this Vector3 v){ return new Vector4(v.z, v.x, v.x, v.y); }
		public static Vector4 ZXXZ(this Vector3 v){ return new Vector4(v.z, v.x, v.x, v.z); }
		public static Vector4 ZXYX(this Vector3 v){ return new Vector4(v.z, v.x, v.y, v.x); }
		public static Vector4 ZXYY(this Vector3 v){ return new Vector4(v.z, v.x, v.y, v.y); }
		public static Vector4 ZXYZ(this Vector3 v){ return new Vector4(v.z, v.x, v.y, v.z); }
		public static Vector4 ZXZX(this Vector3 v){ return new Vector4(v.z, v.x, v.z, v.x); }
		public static Vector4 ZXZY(this Vector3 v){ return new Vector4(v.z, v.x, v.z, v.y); }
		public static Vector4 ZXZZ(this Vector3 v){ return new Vector4(v.z, v.x, v.z, v.z); }
		
		public static Vector4 ZYXX(this Vector3 v){ return new Vector4(v.z, v.y, v.x, v.x); }
		public static Vector4 ZYXY(this Vector3 v){ return new Vector4(v.z, v.y, v.x, v.y); }
		public static Vector4 ZYXZ(this Vector3 v){ return new Vector4(v.z, v.y, v.x, v.z); }
		public static Vector4 ZYYX(this Vector3 v){ return new Vector4(v.z, v.y, v.y, v.x); }
		public static Vector4 ZYYY(this Vector3 v){ return new Vector4(v.z, v.y, v.y, v.y); }
		public static Vector4 ZYYZ(this Vector3 v){ return new Vector4(v.z, v.y, v.y, v.z); }
		public static Vector4 ZYZX(this Vector3 v){ return new Vector4(v.z, v.y, v.z, v.x); }
		public static Vector4 ZYZY(this Vector3 v){ return new Vector4(v.z, v.y, v.z, v.y); }
		public static Vector4 ZYZZ(this Vector3 v){ return new Vector4(v.z, v.y, v.z, v.z); }
		
		public static Vector4 ZZXX(this Vector3 v){ return new Vector4(v.z, v.z, v.x, v.x); }
		public static Vector4 ZZXY(this Vector3 v){ return new Vector4(v.z, v.z, v.x, v.y); }
		public static Vector4 ZZXZ(this Vector3 v){ return new Vector4(v.z, v.z, v.x, v.z); }
		public static Vector4 ZZYX(this Vector3 v){ return new Vector4(v.z, v.z, v.y, v.x); }
		public static Vector4 ZZYY(this Vector3 v){ return new Vector4(v.z, v.z, v.y, v.y); }
		public static Vector4 ZZYZ(this Vector3 v){ return new Vector4(v.z, v.z, v.y, v.z); }
		public static Vector4 ZZZX(this Vector3 v){ return new Vector4(v.z, v.z, v.z, v.x); }
		public static Vector4 ZZZY(this Vector3 v){ return new Vector4(v.z, v.z, v.z, v.y); }
		public static Vector4 ZZZZ(this Vector3 v){ return new Vector4(v.z, v.z, v.z, v.z); }
		#endregion
		#endregion
		
		/*
		public const float SECTOR_SIZE = 32F;
		public const float SECTOR_INV_SIZE = 1F / SECTOR_SIZE;
		public const int SECTOR_MAX = 2047;
		public const int SECTOR_CENTER = SECTOR_MAX >> 1;
		public static Terrain[,] TerrainMap;
		
		public static byte[] GetData(this Vector3 v)
		{
			return v.GetData(Vector3.zero);
		}
		public static byte[] GetData(this Vector3 v, Vector3 prev)
		{
			if(TerrainMap != null)
			{
				byte[] data = new byte[1];
				uint dataPos = 0;
				
				int sectorX = 0;
				int sectorZ = 0;
				int sectorXPrev = 0;
				int sectorZPrev = 0;
				v.GetSector(ref sectorX, ref sectorZ);
				prev.GetSector(ref sectorXPrev, ref sectorZPrev);
				if(sectorX == sectorXPrev && sectorZ == sectorZPrev)
				{
					float height = v.y - TerrainMap[sectorX, sectorZ].SampleHeight(v);
					float heightPrev = prev.y - TerrainMap[sectorXPrev, sectorZPrev].SampleHeight(prev);
					bool heightChange = !height.Aproximates(heightPrev, 0.0625F);
					
					data.WriteBool(heightChange, ref dataPos);
					
					
				}
				
			}
			return null;
		}
		public static void SetData(this Vector3 v, byte[] data)
		{
			if(TerrainMap != null)
			{
				
			}
		}
		public static void GetSector(this Vector3 v, ref int x, ref int z)
		{
			x = SECTOR_CENTER + (int)(v.x * SECTOR_INV_SIZE);
			z = SECTOR_CENTER + (int)(v.z * SECTOR_INV_SIZE);
			if(x > SECTOR_MAX) x = SECTOR_MAX;
			else if(x < 0) x = 0;
			if(z > SECTOR_MAX) z = SECTOR_MAX;
			else if(z < 0) z = 0;
		}
		public static void GetSectorPos(this Vector3 v, ref int x, ref int z)
		{
			x = SECTOR_CENTER + (int)(v.x * SECTOR_INV_SIZE);
			z = SECTOR_CENTER + (int)(v.z * SECTOR_INV_SIZE);
			if(x > SECTOR_MAX) x = SECTOR_MAX;
			else if(x < 0) x = 0;
			if(z > SECTOR_MAX) z = SECTOR_MAX;
			else if(z < 0) z = 0;
			
			//x = (x * SECTOR_SIZE) - v.s
		}
		*/
		
		public static String ToStringSharp(this Vector3 v, int numFractions)
		{
			float power = Mathf.Pow(10F, (float)numFractions);
			float invPower = 1F / power;
			v *= power;
			v.x = ((int)v.x) * invPower;
			v.y = ((int)v.y) * invPower;
			v.z = ((int)v.z) * invPower;
			return "(" + v.x + ", " + v.y + ", " + v.z + ")";
		}
		public static String ToStringSharp(this Vector3 v)
		{
			return v.ToStringSharp(3);
		}
		public static Vector3 Down(this Vector3 v)
		{
			return Vector3.Cross(v.Right().normalized, v);
		}
		public static Vector3 Up(this Vector3 v)
		{
			return Vector3.Cross(v, v.Right().normalized);
		}
		public static Vector3 Right(this Vector3 v)
		{
			return Vector3.Cross(Vector3.up, v);
		}
		public static Vector3 Left(this Vector3 v)
		{
			return Vector3.Cross(v, Vector3.up);
		}
		public static Vector3 DirectionTowards(this Vector3 v, Vector3 other)
		{
			return (other - v).normalized;
		}
		public static Vector3 RandomizeDirection(this Vector3 v, float amount)
		{
			return Quaternion.identity.Randomize(amount) * v;
		}
		public static Vector3 LerpTo(this Vector3 v, Vector3 destination, float amount)
		{
			return Vector3.Lerp(v, destination, amount);
		}
		public static Vector3 SlerpTo(this Vector3 v, Vector3 destination, float amount)
		{
			return Vector3.Slerp(v, destination, amount);
		}
		public static Vector3 SlerpTo(this Vector3 v, Vector3 destination, float amount, Vector3 around)
		{
			return Vector3.Slerp(v - around, destination - around, amount) + around;
		}
		//rotate
		public static Vector3 RotateX(this Vector3 v, float amount)
		{
			return Quaternion.Euler(amount, 0F, 0F) * v;
		}
		public static Vector3 RotateY(this Vector3 v, float amount)
		{
			return Quaternion.Euler(0F, amount, 0F) * v;
		}
		public static Vector3 RotateZ(this Vector3 v, float amount)
		{
			return Quaternion.Euler(0F, 0F, amount) * v;
		}
		public static Vector3 Rotate(this Vector3 v, float x, float y, float z)
		{
			return Quaternion.Euler(x, y, z) * v;
		}
		public static Vector3 Rotate(this Vector3 v, Vector3 eularAngles)
		{
			return Quaternion.Euler(eularAngles) * v;
		}
		//rotate around
		public static Vector3 RotateX(this Vector3 v, float amount, Vector3 around)
		{
			return Quaternion.Euler(amount, 0F, 0F) * (v - around) + around;
		}
		public static Vector3 RotateY(this Vector3 v, float amount, Vector3 around)
		{
			return Quaternion.Euler(0F, amount, 0F) * (v - around) + around;
		}
		public static Vector3 RotateZ(this Vector3 v, float amount, Vector3 around)
		{
			return Quaternion.Euler(0F, 0F, amount) * (v - around) + around;
		}
		public static Vector3 Rotate(this Vector3 v, float x, float y, float z, Vector3 around)
		{
			return Quaternion.Euler(x, y, z) * (v - around) + around;
		}
		public static Vector3 Rotate(this Vector3 v, Vector3 eularAngles, Vector3 around)
		{
			return Quaternion.Euler(eularAngles) * (v - around) + around;
		}
		//to length
		public static Vector3 ToLength(this Vector3 v, float length)
		{
			if(v.x == 0F && v.y == 0F && v.z == 0F)
			{
				v.z = length;
				return v;
			}
			v.Normalize();
			return v * length;
		}
		public static Vector3 ToLength(this Vector3 v, float length, Vector3 from)
		{
			v -= from;
			v.ToLength(length);
			v += from;
			return v;
		}
		public static Vector3 Add(this Vector3 v, float x, float y, float z)
		{
			v.x += x;
			v.y += y;
			v.z += z;
			return v;
		}
		public static Vector3 AddX(this Vector3 v, float value)
		{
			v.x += value;
			return v;
		}
		public static Vector3 AddY(this Vector3 v, float value)
		{
			v.y += value;
			return v;
		}
		public static Vector3 AddZ(this Vector3 v, float value)
		{
			v.z += value;
			return v;
		}
		public static Vector3 SetX(this Vector3 v, float value)
		{
			v.x = value;
			return v;
		}
		public static Vector3 SetY(this Vector3 v, float value)
		{
			v.y = value;
			return v;
		}
		public static Vector3 SetZ(this Vector3 v, float value)
		{
			v.z = value;
			return v;
		}
		public static Vector3 Divide(this Vector3 v, Vector3 divisor)
		{
			v.x /= divisor.x;
			v.y /= divisor.y;
			v.z /= divisor.z;
			return v;
		}
		public static Vector3 Divide(this Vector3 v, float divisor)
		{
			divisor = 1F / divisor;
			v.x *= divisor;
			v.y *= divisor;
			v.z *= divisor;
			return v;
		}
		public static Vector3 Divide(this Vector3 v, float x, float y, float z)
		{
			v.x /= x;
			v.y /= y;
			v.z /= z;
			return v;
		}
		public static Vector3 DivideX(this Vector3 v, float divisor)
		{
			v.x /= divisor;
			return v;
		}
		public static Vector3 DivideY(this Vector3 v, float divisor)
		{
			v.y /= divisor;
			return v;
		}
		public static Vector3 DivideZ(this Vector3 v, float divisor)
		{
			v.z /= divisor;
			return v;
		}
		public static Vector3 GetScaled(this Vector3 v, Vector3 scalar)
		{
			v.x *= scalar.x;
			v.y *= scalar.y;
			v.z *= scalar.z;
			return v;
		}
		public static Vector3 Scale(this Vector3 v, float x, float y, float z)
		{
			v.x *= x;
			v.y *= y;
			v.z *= z;
			return v;
		}
		public static Vector3 ScaleX(this Vector3 v, float scale)
		{
			v.x *= scale;
			return v;
		}
		public static Vector3 ScaleY(this Vector3 v, float scale)
		{
			v.y *= scale;
			return v;
		}
		public static Vector3 ScaleZ(this Vector3 v, float scale)
		{
			v.z *= scale;
			return v;
		}
		
		public static float Dot(this Vector3 v, Vector3 vector)
		{
			return v.x * vector.x + v.y * vector.y + v.z * vector.z;
		}
		public static Vector3 Cross(this Vector3 v, Vector3 vector)
		{
			return new Vector3( v.y * vector.z - v.z * vector.y,
								v.z * vector.x - v.x * vector.z,
								v.x * vector.y - v.y * vector.x);
		}
		public static Vector3 Mirror(this Vector3 v, float mirrorNormalX, float mirrorNormalY, float mirrorNormalZ)
		{
			return Vector3.Reflect(v, new Vector3(mirrorNormalX, mirrorNormalY, mirrorNormalZ));
		}
		public static Vector3 Mirror(this Vector3 v, Plane mirror)
		{
			return Vector3.Reflect(v, mirror.normal);
		}
		public static Vector3 Mirror(this Vector3 v, Vector3 mirrorNormal)
		{
			return Vector3.Reflect(v, mirrorNormal);
		}
		public static Vector3 Bounce(this Vector3 v, Vector3 mirrorNormal, float bounciness)
		{
			bounciness = bounciness.Clamp();
			return Vector3.Reflect(v, mirrorNormal) * bounciness + v.Flatten(mirrorNormal) * (1F - bounciness);
		}
		public static Vector3 Flatten(this Vector3 v)
		{
			v.y = 0F;
			return v;
		}
		public static Vector3 Flatten(this Vector3 v, float xAxis, float yAxis, float zAxis)
		{
			return v - Vector3.Project(v, new Vector3(xAxis, yAxis, zAxis));
		}
		public static Vector3 Flatten(this Vector3 v, Plane onPlane)
		{
			return onPlane.normal * onPlane.distance + v - Vector3.Project(v, onPlane.normal);
		}
		public static Vector3 Flatten(this Vector3 v, Vector3 axisToFlatten)
		{
			return v - Vector3.Project(v, axisToFlatten);
		}
		
		public static Vector3 Flatten(this Vector3 v, float amount)
		{
			v.y *= (1F - amount);
			return v;
		}
		public static Vector3 Flatten(this Vector3 v, float xAxis, float yAxis, float zAxis, float amount)
		{
			return v * (1F - amount) + (v - Vector3.Project(v, new Vector3(xAxis, yAxis, zAxis))) * amount;
		}
		public static Vector3 Flatten(this Vector3 v, Plane onPlane, float amount)
		{
			return v * (1F - amount) + (onPlane.normal * onPlane.distance + v - Vector3.Project(v, onPlane.normal)) * amount;
		}
		public static Vector3 Flatten(this Vector3 v, Vector3 axisToFlatten, float amount)
		{
			return v - Vector3.Project(v, axisToFlatten) * amount;
		}
		public static Vector3 LineTo(this Vector3 v, Color color, Transform t, params Vector3[] points)
		{
			v = v.From(t);
			for(int i = 0; i < points.Length; i++)
			{
				Vector3 v2 = points[i].From(t);
				v.LineTo(v2, color);
				v = v2;
			}
			return v;
		}
		public static Vector3 LineTo(this Vector3 v, Color color, params Vector3[] points)
		{
			for(int i = 0; i < points.Length; i++)
			{
				v.LineTo(points[i], color);
				v = points[i];
			}
			return v;
		}
		public static Vector3 LineTo(this Vector3 v, Transform t, params Vector3[] points)
		{
			v = v.From(t);
			for(int i = 0; i < points.Length; i++)
			{
				Vector3 v2 = points[i].From(t);
				v.LineTo(v2);
				v = v2;
			}
			return v;
		}
		public static Vector3 LineTo(this Vector3 v, params Vector3[] points)
		{
			for(int i = 0; i < points.Length; i++)
			{
				v.LineTo(points[i]);
				v = points[i];
			}
			return v;
		}
		public static Vector3 LineTo(this Vector3 v, Vector3 to)
		{
			Debug.DrawLine(v, to, DebugColor);
			return to;
		}
		public static Vector3 LineTo(this Vector3 v, Vector3 to, Color color)
		{
			Debug.DrawLine(v, to, color);
			return to;
		}
		public static Vector3 RayTo(this Vector3 v, Color color, params Vector3[] rays)
		{
			for(int i = 0; i < rays.Length; i++)
			{
				v.RayTo(rays[i], color);
				v += rays[i];
			}
			return v;
		}
		public static Vector3 RayTo(this Vector3 v, Transform t, params Vector3[] rays)
		{
			v = v.From(t);
			for(int i = 0; i < rays.Length; i++)
			{
				Vector3 v2 = rays[i].FromLocalDirection(t);
				v.RayTo(v2);
				v += v2;
			}
			return v;
		}
		public static Vector3 RayTo(this Vector3 v, params Vector3[] rays)
		{
			for(int i = 0; i < rays.Length; i++)
			{
				v.RayTo(rays[i]);
				v += rays[i];
			}
			return v;
		}
		public static Vector3 RayTo(this Vector3 v, Vector3 to)
		{
			Debug.DrawLine(v, v + to, DebugColor);
			return v + to;
		}
		public static Vector3 RayTo(this Vector3 v, Vector3 to, Color color)
		{
			Debug.DrawLine(v, v + to, color);
			return v + to;
		}
		public static bool IsCloseTo(this Vector3 v, Vector3 to, float threshold)
		{
			return (
				   (v.x - to.x) * (v.x - to.x)
				 + (v.y - to.y) * (v.y - to.y)
				 + (v.z - to.z) * (v.z - to.z)
				   ) < threshold * threshold;
		}
		public static float DistanceTo(this Vector3 v, Vector3 to)
		{
			return (v - to).magnitude;
		}
		public static float DistanceToSqr(this Vector3 v, Vector3 to)
		{
			return (v.x - to.x) * (v.x - to.x)
				 + (v.y - to.y) * (v.y - to.y)
				 + (v.z - to.z) * (v.z - to.z);
		}
		public static Vector3 DrawAt(this Vector3 v, Vector3 position)
		{
			Debug.DrawLine(position, position + v, DebugColor);
			return position + v;
		}
		public static Vector3 DrawAt(this Vector3 v, Vector3 position, Color color)
		{
			Debug.DrawLine(position, position + v, color);
			return position + v;
		}
		public static Vector3 DrawNormalAt(this Vector3 v, Vector3 position)
		{
			v.Normalize();
			Debug.DrawLine(position, position + v, DebugColor);
			return position + v;
		}
		public static Vector3 DrawNormalAt(this Vector3 v, Vector3 position, Color color)
		{
			v.Normalize();
			Debug.DrawLine(position, position + v, color);
			return position + v;
		}
		public static Vector3 FromLocalDirection(this Vector3 v, Transform localSpace)
		{
			return localSpace.TransformDirection(v);
		}
		public static Vector3 ToLocalDirection(this Vector3 v, Transform localSpace)
		{
			return localSpace.InverseTransformDirection(v);
		}
		public static Vector3 From(this Vector3 v, Transform localSpace)
		{
			return localSpace.TransformPoint(v);
		}
		public static Vector3 To(this Vector3 v, Transform localSpace)
		{
			return localSpace.InverseTransformPoint(v);
		}
		public static Vector3 ToSpace(this Vector3 v, Transform sourceSpace, Transform destinationSpace)
		{
			return destinationSpace.InverseTransformPoint(sourceSpace.TransformPoint(v));
		}
		public static Vector3 ToDirectionalSpace(this Vector3 v, Transform sourceSpace, Transform destinationSpace)
		{
			return destinationSpace.InverseTransformDirection(sourceSpace.TransformDirection(v));
		}
		public static Vector3 RandomBetweenPoles(this Vector3 v, Vector3 pole)
		{
			return (UnityEngine.Random.insideUnitSphere * Vector3.Distance(v, pole)) + ((v + pole) * 0.5F);
		}
		public static Vector3 Abs (this Vector3 v)
		{
			return new Vector3 (v.x > 0 ? v.x : -v.x, v.y > 0 ? v.y : -v.y, v.z > 0 ? v.z : -v.z);
		}
		public static Vector3 ClampMin(this Vector3 v, float minX, float minY, float minZ)
		{
			v.x = v.x.Max(minX);
			v.y = v.y.Max(minY);
			v.z = v.z.Max(minZ);
			return v;
		}
		public static Vector3 ClampMin(this Vector3 v, Vector3 min)
		{
			return v.ClampMin(min.x, min.y, min.z);
		}
		public static Vector3 ClampMax(this Vector3 v, float maxX, float maxY, float maxZ)
		{
			v.x = v.x.Min(maxX);
			v.y = v.y.Min(maxY);
			v.z = v.z.Min(maxZ);
			return v;
		}
		public static Vector3 ClampMax(this Vector3 v, Vector3 max)
		{
			return v.ClampMax(max.x, max.y, max.z);
		}
		public static Vector3 Clamp(this Vector3 v, Bounds bounds)
		{
			Vector3 min = bounds.min;
			Vector3 max = bounds.max;
			v.x = v.x.ClampBetween(min.x, max.x);
			v.y = v.y.ClampBetween(min.y, max.y);
			v.z = v.z.ClampBetween(min.z, max.z);
			return v;
		}
		public static Vector3 GetClampedAngles(this Vector3 v)
		{
			while(v.x > 180F) v.x -= 360F;
			while(v.x < -180F) v.x += 360F;
			
			while(v.y > 180F) v.y -= 360F;
			while(v.y < -180F) v.y += 360F;
			
			while(v.z > 180F) v.z -= 360F;
			while(v.z < -180F) v.z += 360F;
			
			return v;
		}
		public static Quaternion RotationEuler(this Vector3 v)
		{
			return Quaternion.Euler(v);
		}
		public static Quaternion Rotation(this Vector3 v)
		{
			return Quaternion.LookRotation(v, Vector3.up);
		}
		public static Vector4 ToVector4(this Vector3 v, float w)
		{
			return new Vector4(v.x, v.y, v.z, w);
		}
		public static Vector2 ToVector2(this Vector3 v)
		{
			return new Vector2(v.x, v.y);
		}
		public static Vector3 GetInversed(this Vector3 v)
		{
			return v * (-1F);
		}
		public static void Detonate(this Vector3 v, float power)
		{
			v.Detonate(power, power * 0.3F, DEFAULT_UPWARDS_MODIFIER, ForceMode.Force);
		}
		public static void Detonate(this Vector3 v, float power, float range)
		{
			v.Detonate(power, range, DEFAULT_UPWARDS_MODIFIER, ForceMode.Force);
		}
		public static void Detonate(this Vector3 v, float power, float range, float upwardsModifier)
		{
			v.Detonate(power, range, upwardsModifier, ForceMode.Force);
		}
		public static void Detonate(this Vector3 v, float power, float range, float upwardsModifier, ForceMode mode)
		{
			Collider[] colliders = Physics.OverlapSphere(v, range);
			foreach(Collider col in colliders)
			{
				if(col.attachedRigidbody)
				{
					col.attachedRigidbody.AddExplosionForce(power, v, range, upwardsModifier, mode);
				}
			}
		}
		public static void Kaboom(this Vector3 v)
		{
			v.Detonate(10000F, 3F, DEFAULT_UPWARDS_MODIFIER, ForceMode.Acceleration);
		}
		public static Vector3 ConstrainMaxMagnitude(this Vector3 v, float maxMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxMagnitude * maxMagnitude)
			{
				return v * ((maxMagnitude * maxMagnitude) / length);
			}
			return v;
		}
		public static Vector3 ConstrainMinMagnitude(this Vector3 v, float minMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length < minMagnitude * minMagnitude)
			{
				return v * ((minMagnitude * minMagnitude) / length);
			}
			return v;
		}
		public static Vector3 ConstrainMagnitude(this Vector3 v, float maxMagnitude, float minMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxMagnitude * maxMagnitude)
			{
				return v * ((maxMagnitude * maxMagnitude) / length);
			}
			else if(length < minMagnitude * minMagnitude)
			{
				return v * ((minMagnitude * minMagnitude) / length);
			}
			return v;
		}
		public static Vector3 ConstrainMaxMagnitudeSqr(this Vector3 v, float maxSqrMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxSqrMagnitude)
			{
				return v * (maxSqrMagnitude / length);
			}
			return v;
		}
		public static Vector3 ConstrainMinMagnitudeSqr(this Vector3 v, float minSqrMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length < minSqrMagnitude)
			{
				return v * (minSqrMagnitude / length);
			}
			return v;
		}
		public static Vector3 ConstrainMagnitudeSqr(this Vector3 v, float maxSqrMagnitude, float minSqrMagnitude)
		{
			float length = v.sqrMagnitude;
			if(length > maxSqrMagnitude)
			{
				return v * (maxSqrMagnitude / length);
			}
			else if(length < minSqrMagnitude)
			{
				return v * (minSqrMagnitude / length);
			}
			return v;
		}
		
		public static Vector3 ProjectOffset(this Vector3 normal, Vector3 point, Transform offset)
		{
			return offset.ToGlobalPoint(Vector3.Project(offset.ToLocalPoint(point), normal));
		}
		public static bool Aproximates(this Vector3 v, Vector3 other, float threshold)
		{
			return Vector3.Distance(v, other) <= threshold;
		}
	}
}

